package com.cooper.mediadb.online;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.cooper.scraper.DefineTag;
import com.cooper.scraper.DownloadException;
import com.cooper.scraper.DownloadParams;
import com.cooper.scraper.ResourceScraper;
import com.cooper.scraper.ResultUrl;
import com.cooper.scraper.Scraper;
import com.cooper.scraper.ScraperException;

public class OnlineMediaScraper extends Scraper implements
		ResourceScraper<OnlineMedia> {

	private static final String BROWSE_URL_TAG = "CreateBrowseUrl";
	private static final String SEARCH_URL_TAG = "CreateSearchUrl";
	private static final String BROWSE_MOVIE_TAG = "BrowseMovie";
	private static final String BROWSE_PAGE_COUNT_TAG = "GetBrowsePageCount";
	private static final String BROWSE_COUNT_TAG = "GetBrowseCount";
	private static final String BROWSE_REDIRECT_COUNT_TAG = "BrowseRedirectCount";
	private static final String SEARCH_COUNT_TAG = "GetSearchCount";
	private static final String SEARCH_REDIRECT_COUNT_TAG = "SearchRedirectCount";
	private static final String SEARCH_PAGE_COUNT_TAG = "GetSearchPageCount";
	private static final String SEARCH_MOVIE_TAG = "SearchMovie";
	private static final String MOVIE_DETAISL_TAG = "GetDetails";
	private static final String BROWSE_REDIRECT_MOVIE_TAG = "BrowseRedirectMovie";
	private static final String SEARCH_REDIRECT_MOVIE_TAG = "SearchRedirectMovie";
	private static final String BROWSE_REDIRECT_PAGE_COUNT_TAG = "BrowseRedirectPageCount";
	private static final String SEARCH_REDIRECT_PAGE_COUNT_TAG = "SearchRedirectPageCount";

	private static final String PAGE_COUNT_CALC_REG = "<count>\\s*(\\d+)\\s*</count>\\s*<page>\\s*(\\d+)\\s*</page>";

	public OnlineMediaScraper(int scraperResId, Map<String, String> params,
			DownloadParams downloadParams) {
		super(scraperResId, params, downloadParams);
	}

	@Override
	public ResultUrl createBrowseUrl(int pageNumber) throws DownloadException,
			ScraperException {
		setBufferValue(1, String.valueOf(pageNumber));
		try {
			DefineTag tag = getDefineTag(BROWSE_URL_TAG);
			return ResultUrl.urlFactory(tag.matchRegExp(), tag.getEncodeType())
					.get(0);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_URL_TAG, e);
		}
	}

	@Override
	public ResultUrl createSearchUrl(String keyword, int pageNumber)
			throws DownloadException, ScraperException {
		setBufferValue(1, keyword);
		setBufferValue(2, String.valueOf(pageNumber));
		try {
			DefineTag tag = getDefineTag(SEARCH_URL_TAG);
			return ResultUrl.urlFactory(tag.matchRegExp(), tag.getEncodeType())
					.get(0);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_URL_TAG, e);
		}
	}

	@Override
	public List<OnlineMedia> extractBrowseResource(String page, String referer)
			throws DownloadException, ScraperException {
		setBufferValue(1, page);
		try {
			DefineTag tag = getDefineTag(BROWSE_MOVIE_TAG);
			return OnlineMedia.onlineMovieFactory(tag.matchRegExp(),
					scraperResId, tag.getEncodeType(), referer);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_MOVIE_TAG, e);
		}
	}

	@Override
	public List<OnlineMedia> extractBrowseResource(String page, String referer,
			String redirectUrl) throws DownloadException, ScraperException {
		setBufferValue(1, page);
		setBufferValue(2, redirectUrl);
		try {
			DefineTag tag = getDefineTag(BROWSE_REDIRECT_MOVIE_TAG);
			if (tag == null) {
				return extractBrowseResource(page, referer);
			} else
				return OnlineMedia.onlineMovieFactory(tag.matchRegExp(),
						scraperResId, tag.getEncodeType(), referer);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_MOVIE_TAG, e);
		}
	}

	@Override
	public List<OnlineMedia> extractSearchResource(String page, String referer)
			throws DownloadException, ScraperException {
		setBufferValue(1, page);
		try {
			DefineTag tag = getDefineTag(SEARCH_MOVIE_TAG);
			return OnlineMedia.onlineMovieFactory(tag.matchRegExp(),
					scraperResId, tag.getEncodeType(), referer);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_MOVIE_TAG, e);
		}
	}

	@Override
	public List<OnlineMedia> extractSearchResource(String page, String referer,
			String redirectUrl) throws DownloadException, ScraperException {
		setBufferValue(1, page);
		setBufferValue(2, redirectUrl);
		try {
			DefineTag tag = getDefineTag(SEARCH_REDIRECT_MOVIE_TAG);
			if (tag == null) {
				return extractSearchResource(page, referer);
			} else
				return OnlineMedia.onlineMovieFactory(tag.matchRegExp(),
						scraperResId, tag.getEncodeType(), referer);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_REDIRECT_MOVIE_TAG, e);
		}
	}

	private int calcPageCount(String exp) {
		if ((exp == null) || "".equals(exp)) {
			return 0;
		} else {
			
			Matcher m = Pattern.compile(PAGE_COUNT_CALC_REG).matcher(exp);
			if (m.find()) {
				if (Integer.parseInt(m.group(1)) == 0){
					return 0;
				}else if (Integer.parseInt(m.group(2)) == 0){
					return Integer.parseInt(m.group(1));
				}
				int result = Integer.parseInt(m.group(1))
						/ Integer.parseInt(m.group(2));
				if ((Integer.parseInt(m.group(1)) % Integer
						.parseInt(m.group(2))) > 0) {
					result++;
				}
				return result;
			} else
				return 0;
		}
	}

	private int getSearchPageFromCount(String page, String redirectUrl)
			throws DownloadException, ScraperException {
		try {
			DefineTag tag = getDefineTag(SEARCH_REDIRECT_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				setBufferValue(2, redirectUrl);
				return calcPageCount(tag.matchRegExp());
			} else {
				return getSearchPageCount(page);
			}
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_REDIRECT_COUNT_TAG, e);
		}
	}

	private int getSearchPageFromCount(String page) throws DownloadException,
			ScraperException {
		setBufferValue(1, page);
		try {
			return calcPageCount(getDefineTag(SEARCH_COUNT_TAG).matchRegExp());
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_COUNT_TAG, e);
		}
	}

	@Override
	public int getSearchPageCount(String page) throws DownloadException,
			ScraperException {
		try {
			DefineTag tag = getDefineTag(SEARCH_PAGE_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				String result = tag.matchRegExp();
				if ((result == null) || "".equals(result)) {
					return 0;
				} else {
					return Integer.parseInt(result);
				}
			} else
				return getSearchPageFromCount(page);

		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_PAGE_COUNT_TAG, e);
		}
	}

	@Override
	public int getSearchPageCount(String page, String redirectUrl)
			throws DownloadException, ScraperException {

		try {
			DefineTag tag = getDefineTag(SEARCH_REDIRECT_PAGE_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				setBufferValue(2, redirectUrl);
				String result = tag.matchRegExp();
				if ((result == null) || "".equals(result)) {
					return 0;
				} else {
					return Integer.parseInt(result);
				}
			} else
				return getSearchPageFromCount(page, redirectUrl);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(SEARCH_REDIRECT_PAGE_COUNT_TAG, e);
		}
	}

	private int getBrowsePageFromCount(String page) throws DownloadException,
			ScraperException {
		setBufferValue(1, page);
		try {
			return calcPageCount(getDefineTag(BROWSE_COUNT_TAG).matchRegExp());
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_COUNT_TAG, e);
		}
	}

	@Override
	public int getBrowsePageCount(String page) throws DownloadException,
			ScraperException {
		try {
			DefineTag tag = getDefineTag(BROWSE_PAGE_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				String result = tag.matchRegExp();
				if ((result == null) || "".equals(result)) {
					return 0;
				} else {
					return Integer.parseInt(result);
				}
			} else
				return getBrowsePageFromCount(page);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_PAGE_COUNT_TAG, e);
		}
	}

	private int getBrowsePageFromCount(String page, String redirectUrl)
			throws DownloadException, ScraperException {
		try {
			DefineTag tag = getDefineTag(BROWSE_REDIRECT_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				setBufferValue(2, redirectUrl);
				return calcPageCount(tag.matchRegExp());
			} else {
				return getBrowsePageCount(page);
			}
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_REDIRECT_COUNT_TAG, e);
		}
	}

	@Override
	public int getBrowsePageCount(String page, String redirectUrl)
			throws DownloadException, ScraperException {
		try {
			DefineTag tag = getDefineTag(BROWSE_REDIRECT_PAGE_COUNT_TAG);
			if (tag != null) {
				setBufferValue(1, page);
				setBufferValue(2, redirectUrl);
				String result = tag.matchRegExp();
				if ((result == null) || "".equals(result)) {
					return 0;
				} else {
					return Integer.parseInt(result);
				}
			} else
				return getBrowsePageFromCount(page, redirectUrl);
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_REDIRECT_PAGE_COUNT_TAG, e);
		}
	}

	@Override
	public String extractDetails(String page, String movieId)
			throws DownloadException, ScraperException {
		setBufferValue(1, page);
		setBufferValue(2, movieId);
		try {
			return getDefineTag(MOVIE_DETAISL_TAG).matchRegExp();
		} catch (DownloadException e) {
			throw e;
		} catch (Exception e) {
			throw new ScraperException(BROWSE_PAGE_COUNT_TAG, e);
		}
	}

}
